package stream.method;

import stream.BookCase;
import stream.StreamsLearn;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @CreateBy zhangdingyi
 * @Date 2022-10-08
 * @Content 1.8 收集结果、1.9 收集到映射表中、
 */
public class Five {
    public static void main(String[] args) {
        //collectResult();
        collectTransform();

        //代码清单
        //testCodeList();
    }

    /**
     * 该数据是否能够改变并非是通过具体的数据来进行的，而是通过数据结构 -堆栈存储的数据来进行的
     * 如果是 栈 则就是临时的，如果是 堆 就是持续的
     * 在栈中的数据修改完毕后就仅作用于相应的作用域
     * <p>
     * 收集结果的程序清单
     * 简单的讲就是一些收集方法的使用
     * 主要的话就是有 两种遍历的方法
     * <p>
     * 一种是仅作于遍历 (iterator) --这个是仅能取值 而不能改变值
     * iterator.next() = iterator.next() + "aa" 这个会报错 因此不能直接操作 具体的数据
     * --------------
     * 另外一种就是 类似 for循环可以把每个参数进行修改 (foreach) 将某个函数应用于每个元素
     * dome = dome + "abc" 可以设置值并且可以正常的输出
     * <p>
     * 但是这个foreach是不按照顺序来处理的，但是可以并行同步的处理这些数据
     * 如果想要按照流中的顺序来处理它们，可以调用
     * forEachOrdered方法。
     * 当然，这个方法会丧失并行处理的部分甚至全部优势。
     */
    static void collectResult() {
        List<String> listStr = StreamsLearn.getListStr();
        //iterator 这个方法实质并不一定属于 stream 只要 有一个具体的集合 就可以进行使用
        //Iterator<String> iterator = listStr.iterator();
        //因此不管是否有 stream 都能使用 iterator 方法
        Iterator<String> iterator = listStr.stream().iterator();
        //iterator.next() = iterator.next() + "aa" 这个会报错 因此不能直接操作 具体的数据
        //while (iterator.hasNext()) System.out.println(iterator.next());
        //for (String s : listStr)
        //System.out.println("iterator -> " + s);

        //然而 forEach 这里是 可以操作具体的 数据，因此可以操作具体的对象
        // -- 但是有一个问题，就是该数据 修改的作用域 仅在 foreach中 ，如果更换成对象则能够持续保存
        //listStr.stream().forEach(dome -> dome = dome + "abc");

        //for (String s : listStr)
        //System.out.println("forEach -> " + s);

        //更换成对象来进行测试
        List<BookCase> listObj = StreamsLearn.getListObj();
        Iterator<BookCase> caseIterator = listObj.stream().iterator();
        System.out.println("------getId-----");
        for (BookCase caseD : listObj) System.out.println(caseD.getId());
        while (caseIterator.hasNext())
            caseIterator.next().setId(123456);
        for (BookCase caseD : listObj) System.out.println(caseD.getId());

        System.out.println("------getName-----");

        for (BookCase caseD : listObj) System.out.println(caseD.getName());
        listObj.stream().forEach(dome -> dome.setName("abc123456"));
        for (BookCase caseD : listObj) System.out.println(caseD.getName());

    }


    /**
     * 集合的转换
     * 分别可以转换成
     * List<String>
     * Set<String>
     * TreeSet<String>
     * toMap(仅对象数组) 1.9 收集到映射表中
     * String joining
     * 产生一个连接字符串的收集器。分隔符会置于字符串之间，而第一个字符串之前可以有前缀，最后一个字符串之后可以有后缀。如果没有指定，那么它们都为空。
     * <p>
     * 还可以利用 Collectors.summarizingInt(BookCase::getId)
     * 获取到 总数、平均数、最大最小值等
     * 产生能够生成（Int|Long|Double）SummaryStatistics对象的收集器，通过它可以获得将mapper应用于每个元素后所产生的结果的个数、总和、平均值、最大值和最小值。
     */
    static void collectTransform() {
        List<String> listStr = StreamsLearn.getListStr();
        //转换成 集合
        List<String> collectList = listStr.stream().collect(Collectors.toList());
        Set<String> collectSet = listStr.stream().collect(Collectors.toSet());
        TreeSet<String> treeSet = listStr.stream().collect(Collectors.toCollection(TreeSet::new));

        //把list 整合成一个字符串 分为 带逗号 和 不带逗号
        String collectStr = listStr.stream().collect(Collectors.joining(","));
        //test,fred,test123,fred123,optional,optional123
        System.out.println("collectStr = " + collectStr);

        String collect = listStr.stream().collect(Collectors.joining());
        //testfredtest123fred123optionaloptional123
        System.out.println("collect = " + collect);

        //对象集合转换数据 成 string 字符集合
        List<BookCase> listObj = StreamsLearn.getListObj();
        String listObjStr = listObj.stream().map(dome -> dome.getId() + "").collect(Collectors.joining(","));
        System.out.println("listObjStr -> " + listObjStr);

        //map 的使用 1.9 收集到映射表中
        Map<Integer, BookCase> caseMap = listObj.stream().collect(Collectors.toMap(BookCase::getId, k -> k, (v1, v2) -> v1));
        //这个修改的时候也会同步修改 listObj
        for (BookCase value : caseMap.values()) {
            value.setName("bookCase");
        }

        // k -> k <=> Function.identity() 这个 k -> k 等价于 Function.identity() 表示 BookCase 实体类
        Map<Integer, BookCase> caseMap2 = listObj.stream().collect(Collectors.toMap(BookCase::getId, Function.identity(), (v1, v2) -> v1));
        //如果数据中有重复的数据 则 (v1,v2) -> v1 添加上这个，可以取第一条v1 或者 第二条数据v2
        //Map<Integer, BookCase> caseMap = listObj.stream().collect(Collectors.toMap(BookCase::getId, o -> o,(v1,v2) -> v1));
        caseMap.forEach((k, v) -> {
            System.out.println("toMap k -> " + k + ", v-> " + v.getName());
        });

        //计算总和
        IntSummaryStatistics summaryStatistics = listObj.stream().collect(Collectors.summarizingInt(BookCase::getId));
        //总数
        long sum = summaryStatistics.getSum();
        //最大值
        int max = summaryStatistics.getMax();
        //计数
        long count = summaryStatistics.getCount();
        //平均数
        double average = summaryStatistics.getAverage();
        System.out.println("总数 = " + sum);
        System.out.println("最大值 = " + max);
        System.out.println("计数 = " + count);
        System.out.println("平均数 = " + average);

    }

    /**
     * 代码清单
     */
    public static void testCodeList() {
        //生成并存储 0~9 的数字
        Iterator<Integer> iter = Stream.iterate(0, n -> n + 1)
                .limit(10).iterator();
        while (iter.hasNext()) {
            System.out.println("iter -> " + iter.next());
        }

        //把生成的数据转换成数组
        //这里的话有两种情况 -
        // 一种是 直接转化成 Object[] （不声明，就默认是这个，默认的话 生成的 Object 不能直接转换成 Integer ）
        Object[] numbers = Stream.iterate(0, n -> n + 1)
                .limit(10)
                .toArray();
        System.out.println("Object  Array -> " + numbers);
        for (int i = 0; i < numbers.length; i++) {
            System.out.println("numbers " + i + " -> " + numbers[i]);
        }

        try {
            Integer number = (Integer) numbers[0];
            System.out.println(" number -> " + number);
            //如果直接转换 会抛出异常 ，说这个 Object 无法转换成 Integer
            Integer[] numbers2 = (Integer[]) numbers;
        } catch (Exception e) {
            System.out.println(e);
        }
        // 一种是 在 toArray(Integer[]::new) 声明需要创建的 数组类型（这个生成对应数组）
        Integer[] numbers3 = Stream.iterate(0, n -> n + 1)
                .limit(10).toArray(Integer[]::new);
        System.out.println("numbers3 -> " + numbers3);

        // 后面几个代码都是已经写好的，可以参考
        List<String> listStr = StreamsLearn.getListStr();
        //转换成 集合
        List<String> collectList = listStr.stream().collect(Collectors.toList());
        Set<String> collectSet = listStr.stream().collect(Collectors.toSet());
        show("collectSet", collectSet);

        TreeSet<String> treeSet = listStr.stream().collect(Collectors.toCollection(TreeSet::new));
        show("treeSet", treeSet);
    }

    public static <T> void show(String label, Set<T> set) {
        System.out.println(label + ": " + set.getClass().getName());
        System.out.println("["
                + set.stream().limit(10).map(Object::toString)
                .collect(Collectors.joining(",")) + "]"
        );
    }


}
